package com.coffee.attachment.excel;


import com.coffee.attachment.ExcelDocumentDTO;
import com.coffee.attachment.NotifyExcelDownloadDTO;
import com.coffee.concurrent.CoffeeExecutorManager;
import com.coffee.core.CoffeeException;
import com.coffee.core.CoffeeHeader;
import com.coffee.core.CoffeeResponseEnum;
import com.coffee.excel.MochaExcel;
import com.coffee.excel.MochaExcelException;
import com.coffee.excel.MochaExcelSheet;
import com.coffee.excel.MochaImportHandler;
import com.coffee.minio.MochaMinioTemplate;
import com.coffee.minio.args.MochaPutObjectArgs;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;

/**
 * @author: songkui
 * @since: 2023/4/20 17:04
 */
@Service
@Slf4j
@AllArgsConstructor
public class MochaImportService {
    private final ExcelHandler excelHandler;
    private final MochaMinioTemplate mochaMinioTemplate;

    /**
     *  导入
     * @param excelCode: excel编号
     * @param file:  导入的excel
     * @return
     * @throws CoffeeException
     */
    public void importExcel(String excelCode, MultipartFile file, CoffeeHeader.UserInfo userInfo ) throws CoffeeException {

        MochaExcelSheet sheet = excelHandler.findExcelSheetByCodeFile(excelCode, null);
        if (null == sheet){
            throw  new CoffeeException(ExcelResponseEnum.ExcelFieldNotSet);
        }

        MochaImportHandler importHandler = ExcelHandlerManager.getImportHandler(excelCode);
        if (null == importHandler){
            throw  new CoffeeException(ExcelResponseEnum.ExcelImportNotHandler);
        }

        //  异步切入点
        CoffeeExecutorManager.getInstance().getSlowExecutor().execute(() -> toImport(importHandler, file, sheet,  excelCode, userInfo));

    }

    private void toImport(MochaImportHandler importHandler, MultipartFile file, MochaExcelSheet sheet, String excelCode, CoffeeHeader.UserInfo userInfo){
        InputStream inputStream = null;
        try {
            inputStream = doImport(importHandler, file.getBytes(), sheet);

            String originalName = file.getOriginalFilename();

            String docCode = ExcelConstant.dateRandom();
            String object = ExcelConstant.buildImportObject(excelCode, docCode);
            String fileName = ExcelConstant.buildImportFileName(originalName);

            MochaPutObjectArgs args = new MochaPutObjectArgs();
            args.setBucket(ExcelConstant.ImportBucket).setObject(object);

            mochaMinioTemplate.uploadObject(args.setStream(inputStream)
                                                .setFileName(fileName)
                                                .setCreator(userInfo.getUserCode()));

            ExcelDocumentDTO documentEntity = new ExcelDocumentDTO();
            documentEntity.setDocUser(userInfo.getUserId());
            documentEntity.setTenantId(userInfo.getTenantId());
            documentEntity.setDocCode(docCode);
            documentEntity.setMinioBucket(ExcelConstant.ImportBucket);
            documentEntity.setMinioObject(object);
            documentEntity.setDocExte(ExcelConstant.ExcelExt);
            documentEntity.setDocTitle("导入结果-"+sheet.getTitle());
            documentEntity.setDocType(MochaDocumentType.Import.code());
            documentEntity.setDocDescribe(fileName);

            Long docId = excelHandler.saveExcelDocument(documentEntity);

            if (null != docId){
                excelHandler.notifyExcelDownload(NotifyExcelDownloadDTO.builder()
                        .docId(docId)
                        .docTitle(documentEntity.getDocTitle())
                        .userId(userInfo.getUserId())
                        .tenantId(userInfo.getTenantId())
                        .build());
            }else {
                sendFailureMessage(userInfo.getUserId(), userInfo.getTenantId(), sheet.getTitle(), "Save import excel document failure");
            }

        } catch (MochaExcelException e) {
            Integer state = e.getState();
            log.error("MochaImportService toImport: code: {}; message: {}", state == null ? e.getMessage() : e.getState(), e.getMessage());
            sendFailureMessage(userInfo.getUserId(), userInfo.getTenantId(),  sheet.getTitle(), e.getMessage());
        }catch (CoffeeException ce) {
            sendFailureMessage(userInfo.getUserId(), userInfo.getTenantId(),  sheet.getTitle(), ce.getState().message());
        } catch (Exception e){
            log.error("MochaImportService toImport", e);
            sendFailureMessage(userInfo.getUserId(), userInfo.getTenantId(),  sheet.getTitle(), "系统异常, 请联系管理员!");
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                log.error("导出excel-关闭流异常：", e);
                sendFailureMessage(userInfo.getUserId(), userInfo.getTenantId(), sheet.getTitle(), "关闭导出流异常!");
            }
        }

    }

    private InputStream doImport(MochaImportHandler importHandler, byte[] excelBytes, MochaExcelSheet sheet)throws  Exception{
        InputStream inputStream;
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            MochaExcel.importExcel(sheet.getFieldList(), sheet.getTitle())
                    .outputStream(outputStream)
                    .importBytes(excelBytes)
                    .importHandler(importHandler)
                    .doImport();

            byte[] bytes = outputStream.toByteArray();
            inputStream = new ByteArrayInputStream(bytes);

        } catch (MochaExcelException e) {
            Integer state = e.getState();
            log.error("DoImport exception: code: {}; message: {}", state == null ? e.getMessage() : e.getState(), e.getMessage());
            throw new CoffeeException(e.getMessage());
        }catch (Exception e){
            log.error("MochaImportService exception ", e);
            throw new CoffeeException(CoffeeResponseEnum.SysException);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                log.error("导出excel-关闭流异常：", e);
            }
        }

        return inputStream;
    }

    private void sendFailureMessage(Long userId, Long tenantId, String docTitle, String exceptionInfo){
        excelHandler.notifyExcelDownload(NotifyExcelDownloadDTO.builder()
                .userId(userId)
                .tenantId(tenantId)
                .docTitle(docTitle)
                .exceptionInfo(Optional.ofNullable(exceptionInfo).orElse("导入Excel未知异常!"))
                .build());
    }

}
